package com.credithc.signature.common.utils;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

public class DateUtil {
    public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
    public static final String DEFAULT_DATETIME_PATTERN = "yyyy年MM月dd日";
    public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";
    public static final String STANDARD_PATTERN = "yyyyMMddHHmmss";
    public static final String STANDARD_DATE_PATTERN = "yyyyMMdd";
    public static final String STANDARD_TIME_PATTERN = "HHmmss";

    private static final ZoneId DEFAULT_ZONEID = ZoneId.systemDefault();

    private DateUtil() {
        throw new UnsupportedOperationException("you can't instantiate me...");
    }

    public static String getDefaultDateTimeStr() {
        return getNowStrByPattern(DEFAULT_PATTERN);
    }

    public static String getStandardDateTimeStr() {
        return getNowStrByPattern(STANDARD_PATTERN);
    }

    public static String getDateStr(LocalDateTime localDateTime) {
        return getNowStrByPattern(localDateTime, DEFAULT_DATETIME_PATTERN);
    }

    public static Date getDateFromStr(String dateTime) {
        LocalDateTime localDateTime = getLocalDateTimeByParam(dateTime, DEFAULT_PATTERN);
        return Date.from(localDateTime.atZone(DEFAULT_ZONEID).toInstant());
    }

    public static Date getDateFromStr2(String dateTime) {
        LocalDateTime localDateTime = getLocalDateTimeByParam(dateTime, STANDARD_PATTERN);
        return Date.from(localDateTime.atZone(DEFAULT_ZONEID).toInstant());
    }

    public static String getStandardDateStr() {
        return getNowStrByPattern(STANDARD_DATE_PATTERN);
    }

    public static String getNowStrByPattern(String pattern) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String getNowStrByPattern(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String getDefaultAppointDateStr(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
    }

    public static String getTimeStr(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN));
    }

    public static String getDefaultAppointDateStr2(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN));
    }

    public static String getDefaultAppointDateStr3(Date date) {
        LocalDateTime localDateTime = getLocalDateTime(date.toInstant());
        return localDateTime.format(DateTimeFormatter.ofPattern(STANDARD_DATE_PATTERN));
    }

    public static LocalDateTime getDefaultDateTime(String str) {
        return getLocalDateTimeByParam(str, DEFAULT_PATTERN);
    }

    public static LocalDateTime getStandardDateTime(String str) {
        return getLocalDateTimeByParam(str, STANDARD_PATTERN);
    }

    public static LocalDateTime getLocalDateTimeByParam(String str, String pattern) {
        return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime getLocalDateTime(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), DEFAULT_ZONEID);
    }

    public static LocalDateTime getLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONEID);
    }

    public static LocalDate getLocalDate(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
    }

    /**
     * localDateTime to date
     *
     * @param localDateTime
     * @return
     */
    public static Date getDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(DEFAULT_ZONEID).toInstant());
    }

    /**
     * 获取两个时间 天数
     *
     * @param dateTime1
     * @param dateTime2
     * @return
     */
    public static int betweenDays(String dateTime1, String dateTime2) {
        return Period.between(getLocalDate(dateTime1), getLocalDate(dateTime2)).getDays();
    }

    /**
     * 获取昨天
     *
     * @return
     */
    public static String getYesterday() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        Date date = Date.from(zonedDateTime.toInstant());
        return getDefaultAppointDateStr2(date);
    }

    /**
     * 获取昨天
     *
     * @return
     */
    public static String getYesterdayStander() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        Date date = Date.from(zonedDateTime.toInstant());
        return getDefaultAppointDateStr3(date);
    }

    /**
     * 获取昨天(日期类型)
     *
     * @return
     */
    public static Date  getYesterdayStanderDate() {
        LocalDate localDate = LocalDate.now().minusDays(1);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        Date date = Date.from(zonedDateTime.toInstant());
        return date;
    }


    public static LocalDateTime getLocalDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONEID);
    }

    /**
     * 获取时间与当前时间 秒数
     *
     * @param date
     * @return
     */
    public static long betweenNowSecond(Date date) {
        LocalDateTime start = DateUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.SECONDS.between(start, LocalDateTime.now());
    }

    /**
     * 获取时间与当前时间 分钟数
     *
     * @param date
     * @return
     */
    public static long betweenNowMinute(Date date) {
        LocalDateTime start = DateUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.MINUTES.between(start, LocalDateTime.now());
    }

    /**
     * 获取时间与当前时间 天数
     *
     * @param date
     * @return
     */
    public static long betweenNowDay(Date date) {
        LocalDateTime start = DateUtil.getLocalDateTime(date.toInstant());
        return ChronoUnit.DAYS.between(start, LocalDateTime.now());
    }

    /**
     * 获取两个时间 月数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long betweenMonths(Date startDate, Date endDate) {
        LocalDateTime startTime = DateUtil.getLocalDateTime(startDate.toInstant());
        LocalDateTime endTime = DateUtil.getLocalDateTime(endDate.toInstant());
        return ChronoUnit.MONTHS.between(startTime, endTime);
    }

    /**
     * 获取两个时间 年数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long betweenYears(Date startDate, Date endDate) {
        LocalDateTime startTime = DateUtil.getLocalDateTime(startDate.toInstant());
        LocalDateTime endTime = DateUtil.getLocalDateTime(endDate.toInstant());
        return ChronoUnit.YEARS.between(startTime, endTime);
    }

    /**
     * 获取现在的时间
     * @return
     */
    public static Date getNowTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        return Date.from(localDateTime.atZone(DEFAULT_ZONEID).toInstant());
    }

    /**
     * 获取当天日期
     *
     * @return
     */
    public static Date getNowDate() {
        LocalDate localDate = LocalDate.now();
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于指定时间天数的日期
     *
     * @param date
     * @param minusDays
     * @return
     */
    public static Date getBeforeDate(Date date, long minusDays) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间月数的日期
     *
     * @param minusMonths
     * @return
     */
    public static Date getBeforeMonth(long minusMonths) {
        LocalDate localDate = LocalDate.now().minusMonths(minusMonths);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间分钟的时间
     *
     * @param minusMinutes
     * @return
     */
    public static String getBeforeMinute(long minusMinutes) {
        LocalDateTime localDateTime = LocalDateTime.now().minusMinutes(minusMinutes);
        return localDateTime.format(DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
    }

    /**
     * 获取早于指定时间分钟的时间
     *
     * @param minusMinutes
     * @return
     */
    public static Date getBeforeMinuteByStartTime(long minusMinutes, Date startTime) {
        LocalDateTime localDateTime = getLocalDateTime(startTime).minusMinutes(minusMinutes);
        ZonedDateTime zonedDateTime = localDateTime.atZone(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于当前时间天数的日期
     *
     * @param minusDays
     * @return
     */
    public static Date getBeforeDate(long minusDays) {
        LocalDate localDate = LocalDate.now().minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取早于指定时间天数的日期
     *
     * @param minusDays
     * @param date
     * @return
     */
    public static Date getBeforeDate(long minusDays, Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        LocalDate localDate = localDateTime.toLocalDate();
        LocalDate localDate1 = localDate.minusDays(minusDays);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取晚于当前时间天数的日期
     *
     * @param plusDays
     * @return
     */
    public static Date getNextDate(long plusDays) {
        LocalDate localDate = LocalDate.now().plusDays(plusDays);
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取当天开始时间
     *
     * @param dateStr
     * @return
     */
    public static Date getTodayStartTime(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN);
        return getDate(localDateTime);
    }

    /**
     * 获取当天结束时间
     *
     * @param dateStr
     * @return
     */
    public static Date getTodayLastTime(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
        LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MAX);
        return getDate(localDateTime);
    }

    /**
     * 获取晚于当前时间下一年
     *
     * @param date
     * @return
     */
    public static Date getNextYear(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.plusYears(1);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取晚于当前时间下一个月
     *
     * @param date
     * @return
     */
    public static Date getNextMonth(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate localDate1 = localDate.plusMonths(1);
        ZonedDateTime zonedDateTime = localDate1.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * localDate to date
     *
     * @param localDate
     * @return
     */
    public static Date localDate2Date(LocalDate localDate) {
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(DEFAULT_ZONEID);
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取当前时间年份
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        return getLocalDateTime(date).getYear();
    }

    /**
     * 获取当前时间月份
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        return getLocalDateTime(date).getMonth().getValue();
    }

    /**
     * 获取当前时间年份、月份
     *
     * @param date
     * @return
     */
    public static String getYearAndMonth(Date date) {
        int year = getLocalDateTime(date).getYear();
        int month = getLocalDateTime(date).getMonth().getValue();
        String monthSuffix = String.format("%02d", month);
        return year + monthSuffix;
    }


    public static Date getFirstTimeOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public static Date getLastTimeOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 59);
        return calendar.getTime();
    }
}
